﻿using System;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel.Channels;
using Needle.Bus.Engine.Utils;
using Needle.Utils.Extensions;

namespace Needle.Bus.Engine
{

    public abstract class EngineComponent : CommunicationObject, IEngineComponent
    {

        #region constructors

        public EngineComponent(string id)
            : this(new NamedMutex(id),id)
        { }

        public EngineComponent(object mutex, string id)
            : base(mutex)
        {
            if (String.IsNullOrEmpty(id))
                throw new ArgumentException("id is null or empty.", "id");
            _id = id;
        }

        #endregion

        private readonly string _id;
        public string Id
        {
            get { return _id; }
        }

        #region timeouts

        protected override TimeSpan DefaultCloseTimeout
        {
            get { return 60.Seconds(); }
        }

        protected override TimeSpan DefaultOpenTimeout
        {
            get { return 60.Seconds(); }
        }

        #endregion

        #region open

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            Action<TimeSpan> onOpenDelegate = OnOpen;
            return onOpenDelegate.BeginInvoke(timeout,callback,state);
        }

        protected abstract override void OnOpen(TimeSpan timeout);

        protected override void OnEndOpen(IAsyncResult result)
        {
            AsyncResult r = (AsyncResult)result;
           ((Action<TimeSpan>) r.AsyncDelegate).EndInvoke(result);
        }

        #endregion

        #region abort

        protected abstract override void OnAbort();

        #endregion

        #region close

        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            Action<TimeSpan> onCloseDelegate = OnClose;
            return onCloseDelegate.BeginInvoke(timeout,callback,state);
        }

        protected abstract override void OnClose(TimeSpan timeout);

        protected override void OnEndClose(IAsyncResult result)
        {
             AsyncResult r = (AsyncResult)result;
           ((Action<TimeSpan>) r.AsyncDelegate).EndInvoke(result);
        }

        #endregion

        public override string ToString()
        {
            if (ThisLock is NamedMutex)
                return GetType().Name + " " + Id + ": Mutex = " + ((NamedMutex)ThisLock).Name;
            else
                return GetType().Name + " " + Id;
        }

    }

}
